﻿using CodeAngel.Domain;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Data;

namespace CodeAngel.UI
{
    class EntityDefViewModel : ViewModel
    {
        #region Constructors

        public EntityDefViewModel(EntityDef thisEntityDef)
        {
            this.EntityDef = thisEntityDef;
            this.UpdatedPropertyDefsCollectionView();
            this.UpdatedAggregateDefsCollectionView();
            this.InitializeRootFilterItem();
            this.InitializeDistinctSubFolders();
        }

        #endregion

        #region EntityDef

        /// <summary>
        /// Gets or sets the EntityDef.
        /// </summary>
        public EntityDef EntityDef
        {
            get { return this._EntityDef; }
            private set
            {
                if (value != this._EntityDef)
                {
                    this._EntityDef = value;
                    this.RaisePropertyChanged("EntityDef");
                }
            }
        }
        private EntityDef _EntityDef;

        #endregion

        #region PropertyDefs
        
        #region PropertyDefsCollectionView

        /// <summary>
        /// Gets or sets the PropertyDefsCollectionView.
        /// </summary>
        public ListCollectionView PropertyDefsCollectionView
        {
            get { return this._PropertyDefsCollectionView; }
            set
            {
                if (value != this._PropertyDefsCollectionView)
                {
                    this._PropertyDefsCollectionView = value;
                    this.RaisePropertyChanged("PropertyDefsCollectionView");
                }
            }
        }
        private ListCollectionView _PropertyDefsCollectionView;


        private void UpdatedPropertyDefsCollectionView()
        {
            if (this.EntityDef == null) return;
            this.PropertyDefsCollectionView = new ListCollectionView(this.EntityDef.PropertyDefs);
            this.PropertyDefsCollectionView.SortDescriptions.Add(new System.ComponentModel.SortDescription("Name", System.ComponentModel.ListSortDirection.Ascending));
        }

        #endregion

        #region OpenPropertyDef

        public void OpenPropertyDef(PropertyDef thisPropertyDef)
        {
            var ViewModel = new PropertyDefViewModel(thisPropertyDef);
            var Window = new PropertyDefWindow();
            Window.DataContext = ViewModel;
            Window.Owner = App.Current.MainWindow;
            Window.ShowDialog();
        }

        /// <summary>
        /// Delegate command that can execute OpenPropertyDef.
        /// </summary>
        public DelegateCommand<PropertyDef> OpenPropertyDefCommand
        {
            get
            {
                if (this._OpenPropertyDefCommand == null) this._OpenPropertyDefCommand = new DelegateCommand<PropertyDef>(OpenPropertyDef);
                return this._OpenPropertyDefCommand;
            }
        }
        private DelegateCommand<PropertyDef> _OpenPropertyDefCommand;

        #endregion

        #region CreateNewPropertyDef

        /// <summary>
        /// Prompts the user to create a new PropertyDef object.
        /// </summary>
        public void CreateNewPropertyDef()
        {
            var NewPropertyDefintion = this.EntityDef.PropertyDefs.AddNew();
            var ViewModel = new PropertyDefViewModel(NewPropertyDefintion);
            var Window = new PropertyDefWindow();
            Window.DataContext = ViewModel;
            Window.Owner = App.Current.MainWindow;
            if (Window.ShowDialog() != true)
            {
                this.EntityDef.PropertyDefs.Remove(NewPropertyDefintion);
            }
        }

        /// <summary>
        /// Delegate command that can execute CreateNewPropertyDef.
        /// </summary>
        public DelegateCommand CreateNewPropertyDefCommand
        {
            get
            {
                if (this._CreateNewPropertyDefCommand == null) this._CreateNewPropertyDefCommand = new DelegateCommand(CreateNewPropertyDef);
                return _CreateNewPropertyDefCommand;
            }
        }
        private DelegateCommand _CreateNewPropertyDefCommand;

        #endregion

        #region CreatePrimaryKeyPropertyDef

        /// <summary>
        /// Creats the primary key PropertyDef for the current EntityDef.
        /// </summary>
        public void CreatePrimaryKeyPropertyDef()
        {
            this.EntityDef.AddPropertyDef_PrimaryKey();
        }

        /// <summary>
        /// Delegate command that can execute CreatePrimaryKeyPropertyDef.
        /// </summary>
        public DelegateCommand CreatePrimaryKeyPropertyDefCommand
        {
            get
            {
                if (this._CreatePrimaryKeyPropertyDefCommand == null) this._CreatePrimaryKeyPropertyDefCommand = new DelegateCommand(CreatePrimaryKeyPropertyDef);
                return _CreatePrimaryKeyPropertyDefCommand;
            }
        }
        private DelegateCommand _CreatePrimaryKeyPropertyDefCommand;

        #endregion

        #region CreateNamePropertyDef

        /// <summary>
        /// Creats the Name PropertyDef for the current EntityDef.
        /// </summary>
        public void CreateNamePropertyDef()
        {
            this.EntityDef.AddPropertyDef_Name();
        }

        /// <summary>
        /// Delegate command that can execute CreateNamePropertyDef.
        /// </summary>
        public DelegateCommand CreateNamePropertyDefCommand
        {
            get
            {
                if (this._CreateNamePropertyDefCommand == null) this._CreateNamePropertyDefCommand = new DelegateCommand(CreateNamePropertyDef);
                return _CreateNamePropertyDefCommand;
            }
        }
        private DelegateCommand _CreateNamePropertyDefCommand;

        #endregion

        #region CreateFriendlyIDPropertyDef

        /// <summary>
        /// Creats the FriendlyID PropertyDef for the current EntityDef.
        /// </summary>
        public void CreateFriendlyIDPropertyDef()
        {
            this.EntityDef.AddPropertyDef_FriendlyID();
        }

        /// <summary>
        /// Delegate command that can execute CreateFriendlyIDPropertyDef.
        /// </summary>
        public DelegateCommand CreateFriendlyIDPropertyDefCommand
        {
            get
            {
                if (this._CreateFriendlyIDPropertyDefCommand == null) this._CreateFriendlyIDPropertyDefCommand = new DelegateCommand(CreateFriendlyIDPropertyDef);
                return _CreateFriendlyIDPropertyDefCommand;
            }
        }
        private DelegateCommand _CreateFriendlyIDPropertyDefCommand;

        #endregion

        #region CreateNotesPropertyDef

        /// <summary>
        /// Creats the Notes PropertyDef for the current EntityDef.
        /// </summary>
        public void CreateNotesPropertyDef()
        {
            this.EntityDef.AddPropertyDef_Notes();
        }

        /// <summary>
        /// Delegate command that can execute CreateNotesPropertyDef.
        /// </summary>
        public DelegateCommand CreateNotesPropertyDefCommand
        {
            get
            {
                if (this._CreateNotesPropertyDefCommand == null) this._CreateNotesPropertyDefCommand = new DelegateCommand(CreateNotesPropertyDef);
                return _CreateNotesPropertyDefCommand;
            }
        }
        private DelegateCommand _CreateNotesPropertyDefCommand;

        #endregion

        #region DeletePropertyDef

        /// <summary>
        /// Flags the identified PropertyDefintion as deleted.  Won't actually be deleted until the 
        /// next save operation on the respective aggregate.
        /// </summary>
        public void DeletePropertyDef(PropertyDef thisPD)
        {
            thisPD.Delete();
        }

        /// <summary>
        /// Delegate command that can execute DeletePropertyDef.
        /// </summary>
        public DelegateCommand<PropertyDef> DeletePropertyDefCommand
        {
            get
            {
                if (this._deletePropertyDefCommand == null) this._deletePropertyDefCommand = new DelegateCommand<PropertyDef>(DeletePropertyDef);
                return this._deletePropertyDefCommand;
            }
        }
        private DelegateCommand<PropertyDef> _deletePropertyDefCommand;

        #endregion

        #endregion

        #region AggregateDefs

        #region AggregateDefsCollectionView

        /// <summary>
        /// Gets or sets the AggregateDefsCollectionView.
        /// </summary>
        public ListCollectionView AggregateDefsCollectionView
        {
            get { return this._AggregateDefsCollectionView; }
            set
            {
                if (value != this._AggregateDefsCollectionView)
                {
                    this._AggregateDefsCollectionView = value;
                    this.RaisePropertyChanged("AggregateDefsCollectionView");
                }
            }
        }
        private ListCollectionView _AggregateDefsCollectionView;


        private void UpdatedAggregateDefsCollectionView()
        {
            if (this.EntityDef == null) return;
            this.AggregateDefsCollectionView = new ListCollectionView(this.EntityDef.AggregateDefs);
            this.AggregateDefsCollectionView.SortDescriptions.Add(new System.ComponentModel.SortDescription("Name", System.ComponentModel.ListSortDirection.Ascending));
        }

        #endregion

        #region OpenAggregateDef

        public void OpenAggregateDef(AggregateDef thisAggregateDef)
        {
            var ViewModel = new AggregateDefViewModel(thisAggregateDef);
            var Window = new AggregateDefWindow();
            Window.DataContext = ViewModel;
            Window.Owner = App.Current.MainWindow;
            Window.ShowDialog();
            if (!thisAggregateDef.IsValid())
                if (MessageBox.Show(thisAggregateDef.GetInvalidRules().ToString(), "Aggregate def not valid", MessageBoxButton.OKCancel) == MessageBoxResult.Cancel)
                    this.OpenAggregateDef(thisAggregateDef);
        }

        /// <summary>
        /// Delegate command that can execute OpenAggregateDef.
        /// </summary>
        public DelegateCommand<AggregateDef> OpenAggregateDefCommand
        {
            get
            {
                if (this._OpenAggregateDefCommand == null) this._OpenAggregateDefCommand = new DelegateCommand<AggregateDef>(OpenAggregateDef);
                return this._OpenAggregateDefCommand;
            }
        }
        private DelegateCommand<AggregateDef> _OpenAggregateDefCommand;

        #endregion

        #region CreateNewAggregateDef

        /// <summary>
        /// Prompts the user to create a new AggregateDef object.
        /// </summary>
        public void CreateNewAggregateDef()
        {
            var NewAggregateDefintion = this.EntityDef.AggregateDefs.AddNew();
            var ViewModel = new AggregateDefViewModel(NewAggregateDefintion);
            var Window = new AggregateDefWindow();
            Window.DataContext = ViewModel;
            Window.Owner = App.Current.MainWindow;
            if (Window.ShowDialog() != true)
            {
                this.EntityDef.AggregateDefs.Remove(NewAggregateDefintion);
            }
        }

        /// <summary>
        /// Delegate command that can execute CreateNewAggregateDef.
        /// </summary>
        public DelegateCommand CreateNewAggregateDefCommand
        {
            get
            {
                if (this._CreateNewAggregateDefCommand == null) this._CreateNewAggregateDefCommand = new DelegateCommand(CreateNewAggregateDef);
                return _CreateNewAggregateDefCommand;
            }
        }
        private DelegateCommand _CreateNewAggregateDefCommand;

        #endregion

        #region DeleteAggregateDef

        /// <summary>
        /// Flags the identified AggregateDefintion as deleted.  Won't actually be deleted until the 
        /// next save operation on the respective aggregate.
        /// </summary>
        public void DeleteAggregateDef(AggregateDef thisPD)
        {
            thisPD.Delete();
        }

        /// <summary>
        /// Delegate command that can execute DeleteAggregateDef.
        /// </summary>
        public DelegateCommand<AggregateDef> DeleteAggregateDefCommand
        {
            get
            {
                if (this._deleteAggregateDefCommand == null) this._deleteAggregateDefCommand = new DelegateCommand<AggregateDef>(DeleteAggregateDef);
                return this._deleteAggregateDefCommand;
            }
        }
        private DelegateCommand<AggregateDef> _deleteAggregateDefCommand;

        #endregion

        #endregion

        #region RootFilterItem

        /// <summary>
        /// The RootFilterItem is used to display the Filter of the current EntityDef
        /// and enable the user to modify it.
        /// </summary>
        public FilterRelationItem RootFilterRelationItem
        {
            get { return this._rootFilterRelationItem; }
            set
            {
                if (value != this._rootFilterRelationItem)
                {
                    this._rootFilterRelationItem = value;
                    this.RaisePropertyChanged("Filter");
                }
            }
        }
        private FilterRelationItem _rootFilterRelationItem;

        private void InitializeRootFilterItem()
        {
            if (this.EntityDef.FilterRelation == null) this.EntityDef.CreateFilterRelation();
            this.RootFilterRelationItem = new FilterRelationItem(this.EntityDef);
        }
        #endregion

        #region DistinctSubFolders

        /// <summary>
        /// Gets or sets the DistinctSubFolders.
        /// </summary>
        public ObservableCollection<string> DistinctSubFolders
        {
            get { return this._DistinctSubFolders; }
            set
            {
                if (value != this._DistinctSubFolders)
                {
                    this._DistinctSubFolders = value;
                    this.RaisePropertyChanged("DistinctSubFolders");
                }
            }
        }
        private ObservableCollection<string> _DistinctSubFolders = new ObservableCollection<string>();

        private void InitializeDistinctSubFolders()
        {
            var SubFolders = new ObservableCollection<string>();
            SubFolders.Add(string.Empty);
                foreach (var ThisED in this.EntityDef.Domain.EntityDefs)
                    if (!SubFolders.Contains(ThisED.SubFolder))
                        SubFolders.Add(ThisED.SubFolder);
            this.DistinctSubFolders = SubFolders;
        }

        #endregion

    }

    public class FilterRelationItem : ViewModel
    {
        #region Contructors

        /// <summary>
        /// Constructor solely for the root FilterRelation of an EntityDef
        /// </summary>
        public FilterRelationItem(EntityDef EntityDef)
        {
            this._isInitializing = true;
            this._EntityDef = EntityDef;
            this._root = this;
            this.FilterRelation = this._EntityDef.FilterRelation;
            this.Header = EntityDef.Name;
            this.IsExpanded = true;
            this.IsCheckedVisibility = Visibility.Hidden;
            this.AddChidItems(this._EntityDef.PropertyDefs, this, this.FilterRelation.FilterRelations);
            this._isInitializing = false;
        }
        private EntityDef _EntityDef;
        private FilterRelationItem _root;
        private bool _isInitializing;


        private FilterRelationItem(FilterRelationItem parent, PropertyDef PropertyDef)
        {
            this.Parent = parent;
            this._root = parent._root;
            this._EntityDef = this._root._EntityDef;
            this._EntityDefViewModel = parent._EntityDefViewModel;
            this._PropertyDef = PropertyDef;
            this.Header = this._PropertyDef.Name;

        }
        private PropertyDef _PropertyDef;
        private EntityDefViewModel _EntityDefViewModel;

        #endregion

        #region Header

        /// <summary>
        /// Gets or sets the Header.
        /// </summary>
        public string Header
        {
            get { return this._header; }
            set
            {
                if (value != this._header)
                {
                    this._header = value;
                    this.RaisePropertyChanged("Header");
                }
            }
        }
        private string _header;

        #endregion

        #region Children

        public ObservableCollection<FilterRelationItem> Children
        {
            get { return this._children; }
        }
        private ObservableCollection<FilterRelationItem> _children = new ObservableCollection<FilterRelationItem>();

        private void AddChidItems(PropertyDefCollection PropertyDefs, 
                                  FilterRelationItem parentFilterRelationItem,
                                  FilterRelationCollection filterRelations)
        {
            foreach (var ThisPropertyDef in PropertyDefs.EntityOrCollectionProperties)
            {
                if (parentFilterRelationItem._PropertyDef == null || ThisPropertyDef.DataTypeEntityDef != parentFilterRelationItem._PropertyDef.ParentEntity)
                {
                    var ThisFilterRelationItem = new FilterRelationItem(parentFilterRelationItem, ThisPropertyDef);
                    ThisFilterRelationItem.IsExpanded = true;
                    parentFilterRelationItem.Children.Add(ThisFilterRelationItem);
                    var ThisFilterRelation = filterRelations.Find(ThisPropertyDef);
                    if (ThisFilterRelation != null)
                    {
                        ThisFilterRelationItem.IsChecked = true;
                        ThisFilterRelationItem.FilterRelation = ThisFilterRelation;
                        this.AddChidItems(ThisPropertyDef.DataTypeEntityDef.PropertyDefs, ThisFilterRelationItem, ThisFilterRelation.FilterRelations);
                    }
                }
            }    
        }

        private void RemoveChidlrenItems()
        {
            this.Children.Clear();
        }

        #endregion

        #region Parent

        public FilterRelationItem Parent { get; set; }

        #endregion

        #region FilterRelation

        public FilterRelation FilterRelation { get; set; }

        private void CreateFilterRelation()
        {
            if (this.FilterRelation != null) return;

            this.FilterRelation = this.Parent.FilterRelation.FilterRelations.AddNew();
            this.FilterRelation.EntityDef = this._root._EntityDef;

            this.FilterRelation.PropertyDef = this._PropertyDef;
        }

        private void RemoveFilterRelation()
        {
            if (this.FilterRelation != null)
                this.RemoveFilterRelationAndChildren(this.FilterRelation);
        }

        private void RemoveFilterRelationAndChildren(FilterRelation thisFR)
        {
            if (thisFR == null) return;

            foreach (var ChildFR in thisFR.FilterRelations)
                this.RemoveFilterRelationAndChildren(ChildFR);
            thisFR.Delete();
        }

        #endregion

        #region IsExpanded

        /// <summary>
        /// Gets or sets the IsExpanded.
        /// </summary>
        public bool IsExpanded
        {
            get { return this._isExpanded; }
            set
            {
                if (value != this._isExpanded)
                {
                    this._isExpanded = value;
                    this.RaisePropertyChanged("IsExpanded");
                }
            }
        }
        private bool _isExpanded = false;

        #endregion

        #region IsChecked

        /// <summary>
        /// Gets or sets the IsChecked.
        /// </summary>
        public bool IsChecked
        {
            get { return this._isChecked; }
            set
            {
                if (value != this._isChecked)
                {
                    this._isChecked = value;
                    this.RaisePropertyChanged("IsChecked");

                    if (!this._root._isInitializing)


                    {
                        if (this._isChecked)
                        {
                            this.CreateFilterRelation();
                            this.AddChidItems(this._PropertyDef.DataTypeEntityDef.PropertyDefs, this, this.FilterRelation.FilterRelations);
                        }
                        else
                        {
                            this.RemoveFilterRelation();
                            this.RemoveChidlrenItems();
                        }
                    }

                }
            }
        }
        private bool _isChecked;

        /// <summary>
        /// Gets or sets the IsCheckedVisibility.
        /// </summary>
        public Visibility IsCheckedVisibility
        {
            get { return this._IsCheckedVisibility; }
            set
            {
                if (value != this._IsCheckedVisibility)
                {
                    this._IsCheckedVisibility = value;
                    this.RaisePropertyChanged("IsCheckedVisibility");
                }
            }
        }
        private Visibility _IsCheckedVisibility;

        #endregion

    }
}
